package prender;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.ExecutorService;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

public class Guardian implements Filter {

	private static final Logger logger = Logger.getLogger("Guardian");
	
	private ExecutorService threadPool = null;
	
	@Override
	public void init(FilterConfig config) throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("init: enter");
		}
		ServletContext servletContext = config.getServletContext();
		threadPool = (ExecutorService)servletContext.getAttribute(ApplicationListener.THREAD_POOL_KEY);
		if (threadPool == null) {
			if (logger.isDebugEnabled()) {
				logger.debug("init: thread pool not found");
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("init: leave");
		}
	}
	
	@Override
	public void destroy() {
		if (logger.isDebugEnabled()) {
			logger.debug("destroy");
		}
	}
	
	@Override
	public void doFilter(
			ServletRequest request, 
			ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// long begin = (new Date()).getTime();
		if (logger.isDebugEnabled()) {
			logger.debug("doFilter: enter");
			logger.debug(String.format("doFilter: request = [%s], response = [%s]", 
				Utility.getObjectSignature(request), 
				Utility.getObjectSignature(response))); 
		}
		
		TopContext topContext = null;
		
		ServletRequest realRequest = request;
		ServletResponse realResponse = response;
		
		do {
			// bypass if thread pool is not found
			if (threadPool == null) {
				if (logger.isDebugEnabled()) {
					logger.debug("doFilter: bypass since thread pool not found");
				}
				break;
			}
			
			// bypass if not a http request
			if (!(request instanceof HttpServletRequest)) {
				if (logger.isDebugEnabled()) {
					logger.debug("doFilter: not a  HTTP request, bypass");
				}
				break;
			}
			
			HttpServletRequest hReq  = (HttpServletRequest)request;
			HttpServletResponse hRes = (HttpServletResponse)response;
			
			topContext = new TopContext(response.getWriter(), threadPool);
			topContext.initialize(hReq,  hRes);
			
			realRequest = topContext.request;
			realResponse = topContext.response;
		} while (false);

		if (logger.isDebugEnabled()) {
			logger.debug(String.format("doFilter: before calling chain.doFilter, request = [%s], response = [%s], topContext = [%s]", 
				Utility.getObjectSignature(realRequest),
				Utility.getObjectSignature(realResponse),
				Utility.getObjectSignature(topContext)));
		}
		chain.doFilter(realRequest, realResponse);
		
		if (topContext != null) {
			try {
				topContext.waitForComplete();
			} catch (IOException e) {
				
			}
		}
		// long end = (new Date()).getTime();
		/*
		response.getWriter().printf("Total time: %d (ms)", end - begin);
		response.getWriter().printf("Begin: %d<br />", begin);
		response.getWriter().printf("End  : %d<br />", end);
		*/
		if (logger.isDebugEnabled()) {
			logger.debug("doFilter: leave");
		}
	}

}
